package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_REQUIRE;
import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_VIPFREE;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    /**
     * 保存声音，发起内容审核任务
     *
     * @param trackInfoVo
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //1.根据专辑ID查询专辑信息 得到现有声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        Integer includeTrackCount = albumInfo.getIncludeTrackCount();

        //2.保存声音记录
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //2.1 封装普通属性
        trackInfo.setUserId(userId);
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING); //审核中
        if (StringUtils.isBlank(trackInfo.getCoverUrl())) {
            //如果前端未提交封面，使用专辑封面
            trackInfo.setCoverUrl(albumInfo.getCoverUrl());
        }
        //2.2 计算声音排序值
        trackInfo.setOrderNum(includeTrackCount + 1);
        //2.3 调用点播平台获取音频文件详情得到：时长、大小、类型
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        //2.4 保存声音
        baseMapper.insert(trackInfo);
        Long trackId = trackInfo.getId();

        //3.保存声音统计
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);

        //4.更新专辑包含声音数量
        albumInfo.setIncludeTrackCount(includeTrackCount + 1);
        albumInfoMapper.updateById(albumInfo);

        //5.TODO 发起异步音视频审核任务 更新声音表 审核任务ID
        //5.1 方式一：如果是异步开启线程发起审核任务，将更新声音表逻辑放在审核方法里。不需要返回结果
        //5.2 方式二：如果是同步程发起审核任务，得到审核任务ID，同步更新声音表
        String reviewTaskId = vodService.startReviewTask(trackInfo.getMediaFileId());
        trackInfo.setReviewTaskId(reviewTaskId);
        trackInfoMapper.updateById(trackInfo);
    }

    @Override
    public void saveTrackStat(Long trackId, String statType, int statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 获取当前用户声音分页列表
     *
     * @param pageInfo
     * @param trackInfoQuery
     * @return
     */
    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(pageInfo, trackInfoQuery);
    }

    /**
     * 修改声音
     *
     * @param id
     * @param trackInfoVo
     */
    @Override
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        //1.根据声音ID查询声音记录 获取原来音频ID
        TrackInfo trackInfo = baseMapper.selectById(id);
        String oldMediaFileId = trackInfo.getMediaFileId();
        if (!oldMediaFileId.equals(trackInfoVo.getMediaFileId())) {
            //2.有变更 再次获取最新文件音频信息 更新：时长、大小、类型
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            if (trackMediaInfoVo != null) {
                trackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
                trackInfo.setMediaUrl(trackInfoVo.getMediaUrl());
                trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
                trackInfo.setMediaSize(trackMediaInfoVo.getSize());
                trackInfo.setMediaType(trackMediaInfoVo.getType());
            }
            //3.从点播平台删除旧的音频
            log.info("更新专辑线程：{}", Thread.currentThread().getName());
            vodService.deleteMedia(oldMediaFileId);
            //TODO 变更后音频文件发起审核任务，重新关联审核任务ID
            //5.TODO 发起异步音视频审核任务 更新声音表 审核任务ID
            //5.1 方式一：如果是异步开启线程发起审核任务，将更新声音表逻辑放在审核方法里。不需要返回结果
            //5.2 方式二：如果是同步程发起审核任务，得到审核任务ID，同步更新声音表
            String reviewTaskId = vodService.startReviewTask(trackInfo.getMediaFileId());
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
            trackInfo.setReviewTaskId(reviewTaskId);
            trackInfoMapper.updateById(trackInfo);
        }
        //其他属性更新
        trackInfo.setTrackTitle(trackInfoVo.getTrackTitle());
        trackInfo.setCoverUrl(trackInfoVo.getCoverUrl());
        trackInfo.setTrackIntro(trackInfoVo.getTrackIntro());
        trackInfo.setIsOpen(trackInfoVo.getIsOpen());
        baseMapper.updateById(trackInfo);
    }

    /**
     * 删除声音
     *
     * @param id 声音ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //1.根据声音ID查询被删除声音记录 得到专辑ID及声音序号
        TrackInfo trackInfo = baseMapper.selectById(id);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();
        //2.更新该下专辑下声音序号确保连续
        LambdaUpdateWrapper<TrackInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TrackInfo::getAlbumId, albumId);
        updateWrapper.gt(TrackInfo::getOrderNum, orderNum);
        updateWrapper.setSql("order_num = order_num - 1");
        baseMapper.update(null, updateWrapper);

        //3.删除声音记录
        baseMapper.deleteById(id);

        //4.删除声音统计
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, id));

        //5.更新专辑包含声音数量-1
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        //6.删除点播平台音频文件
        vodService.deleteMedia(trackInfo.getMediaFileId());
    }

    /**
     * 分页查询指定专辑下声音列表，综合根据登录状态、用户身份、购买情况显示付费标识
     *
     * @param pageInfo 分页对象
     * @param albumId  专辑ID
     * @param userId   用户ID
     * @return
     */
    @Override
    public Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
        //1.根据专辑ID分页查询声音列表 TODO 暂不考虑处理付费标识 isShowPaidMark默认：false
        pageInfo = baseMapper.findAlbumTrackPage(pageInfo, albumId);
        //2.根据专辑ID查询专辑信息 得到付费类型以及面试试听集数
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //付费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        Integer tracksForFree = albumInfo.getTracksForFree();
        //3.处理未登录情况
        if (userId == null) {
            //3.1 付费类型为VIP免费/付费。过滤出当前页中声音所有声音序号大于免费试听将付费标识改为true
            if (ALBUM_PAY_TYPE_VIPFREE.equals(payType) || ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                pageInfo.getRecords()
                        .stream()
                        //获取当前页声音序号大于免费试听的
                        .filter(track -> track.getOrderNum() > tracksForFree)
                        //付费标识改为true
                        .forEach(track -> track.setIsShowPaidMark(true));
            }
        } else {
            //3. 处理已登录情况
            //3.1 远程调用用户服务获取用户身份 判断是否为VIP
            Boolean isVIP = false;
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //VIP用户要求：VIP标识等于1且会员在有效期内
                isVIP = true;
            }
            //3.2 是否需要进一步判断声音购买情况变量：false
            Boolean needCheckBuyState = false;

            //3.2.1 如果是普通用户查看付费类型为“VIP免费”专辑，进一步查询当前页面中声音购买情况
            if (!isVIP && ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
                needCheckBuyState = true;
            }
            //3.2.2 所有用户查看付费类型为“付费”专辑，进一步查询当前页面中声音购买情况
            if (ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                needCheckBuyState = true;
            }

            //3.3 如果需要进一步判断声音购买情况，远程调用用户服务获取每个声音购买情况(去除试听声音ID)
            if (needCheckBuyState) {
                //3.3.1 去除掉本页中试听声音ID得到待检查购买情况声音ID列表
                List<Long> needCheckBuyStateTrackIds = pageInfo.getRecords()
                        .stream()
                        .filter(track -> track.getOrderNum() > tracksForFree)
                        .map(AlbumTrackListVo::getTrackId)
                        .collect(Collectors.toList());
                //3.3.2 远程调用用户服务获取每个声音购买情况
                Map<Long, Integer> trackBuyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();
                //3.4 根据购买情况设置付费标识(去除试听声音ID)，未购买声音将标识设置为：true
                if (CollUtil.isNotEmpty(trackBuyStateMap)) {
                    pageInfo.getRecords()
                            .stream()
                            .filter(track -> track.getOrderNum() > tracksForFree)
                            .forEach(albumTrackVo -> albumTrackVo.setIsShowPaidMark(trackBuyStateMap.get(albumTrackVo.getTrackId()) == 0));
                }
            }
        }
        return pageInfo;
    }

    /**
     * 查询声音统计信息
     *
     * @param trackId
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }

    /**
     * 更新数据库中声音表以及专辑表统计数值
     *
     * @param mqVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackStat(TrackStatMqVo mqVo) {
        //1.更新声音表统计数值
        trackStatMapper.update(
                null,
                new LambdaUpdateWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, mqVo.getTrackId())
                        .eq(TrackStat::getStatType, mqVo.getStatType())
                        .setSql("stat_num = stat_num + " + mqVo.getCount())
        );
        //2.如果统计类型是：播放量、评论量 同时更新所属专辑统计数值
        if (SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY)
                            .setSql("stat_num = stat_num + " + mqVo.getCount())
            );
        }
        if (SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT)
                            .setSql("stat_num = stat_num + " + mqVo.getCount())
            );
        }
    }

    /**
     * 基于用户未购买声音数量动态构建分集购买列表
     *
     * @param trackId 选择购买（起始位置）声音ID
     * @return {data:[{name:"本集",price:0.2,trackCount:1},{name:"后10集",price:2,trackCount:10},{...},{name:"全集",price:4.4,trackCount:22}]}
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long userId, Long trackId) {
        //1.根据选择起始声音ID查询声音记录 得到：声音序号、专辑ID
        TrackInfo trackInfo = baseMapper.selectById(trackId);
        Integer orderNum = trackInfo.getOrderNum();
        Long albumId = trackInfo.getAlbumId();
        //2.根据声音序号 专辑ID 按照序号升序 得到"待购买"声音列表（可能包含用户已购买）
        List<TrackInfo> waitBuyTrackInfoList = baseMapper.selectList(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        .ge(TrackInfo::getOrderNum, orderNum)
                        .orderByAsc(TrackInfo::getOrderNum)
        );

        //3.远程调用"用户服务"查询该专辑已购声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();
        if (CollUtil.isNotEmpty(userPaidTrackIdList)) {
            //4.处理"待购买"声音列表，过滤掉用户已购声音ID
            waitBuyTrackInfoList = waitBuyTrackInfoList
                    .stream()
                    .filter(trackInfo1 -> !userPaidTrackIdList.contains(trackInfo1.getId()))
                    .collect(Collectors.toList());
        }
        //5.得到"最终待购买"声音列表，根据列表长度动态构建分集购买列表（最多显示后50级）
        int size = waitBuyTrackInfoList.size();
        List<Map<String, Object>> list = new ArrayList<>();
        //5.1 构建本集分集购买对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        BigDecimal price = albumInfo.getPrice();
        Map<String, Object> curr = new HashMap<>();
        curr.put("name", "本集");
        curr.put("price", price);
        curr.put("trackCount", 1);
        list.add(curr);
        //5.2 构建其他分集购买对象 后10集 后20集 ... 全集   未购买数量：35     25
        for (int i = 10; i <= 50; i += 10) {
            Map<String, Object> map = new HashMap<>();
            if (size > i) {
                map.put("name", "后" + i + "集");
                map.put("price", price.multiply(BigDecimal.valueOf(i)));
                map.put("trackCount", i);
                list.add(map);
            } else {
                map.put("name", "全集(后" + size + "集)");
                map.put("price", price.multiply(BigDecimal.valueOf(size)));
                map.put("trackCount", size);
                list.add(map);
                break;
            }
        }
        return list;
    }

    /**
     * 查询指定用户未购买声音列表
     * @param userId 用户ID
     * @param trackId 声音ID 作为起始声音
     * @param trackCount 声音数量
     * @return
     */
    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long userId, Long trackId, Integer trackCount) {
        //1.根据选择起始声音ID查询声音记录 得到：声音序号、专辑ID
        TrackInfo trackInfo = baseMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();

        //2.远程调用"用户服务"得到已购买声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();

        //3.根据声音序号(大于等于) 、专辑ID（等值）、声音ID（已购买排除） 按照序号升序、指定查询字段、返回购买数量声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, albumId);
        queryWrapper.ge(TrackInfo::getOrderNum, orderNum);
        if(CollUtil.isNotEmpty(userPaidTrackIdList)){
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        queryWrapper.orderByAsc(TrackInfo::getOrderNum);
        //多查询一列专辑ID，为了获取声音价格
        queryWrapper.select(TrackInfo::getId,TrackInfo::getTrackTitle,TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
        //按照用户选择购买数量返回
        queryWrapper.last("limit "+trackCount);

        //4.返回结果
        return baseMapper.selectList(queryWrapper);
    }


}
